﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Net;
using System.Web.SessionState;
using System.IO;
using XMK.Utils;

namespace XMK.Framework.Web
{
    /// <summary>
    /// 带认证的文件下载父类
    /// </summary>
    public class DownloadFileHandler : SecureHttpHandlerBase,IRequiresSessionState
    {
        /// <summary>
        /// 文件类型（HTTP MIME）
        /// </summary>
        public string ContentType { get; set; }
        /// <summary>
        /// 是否在线打开
        /// </summary>
        public bool IsInline { get; set; }
        /// <summary>
        /// 文件下载后显示名称
        /// </summary>
        public string AttachName { get; set; }
        /// <summary>
        /// 文件下载地址
        /// </summary>
        public string AttachUrl { get; set; }

        /// <summary>
        /// 处理文件请求
        /// </summary>
        public override void Process()
        {
            if (Context.Request["attatch"] == null || Context.Request["filecat"] == null)
                return;
            
            this.AttachUrl = Context.Request["attatch"];
            this.AttachName = this.AttachUrl.Substring(this.AttachUrl.LastIndexOf("/") + 1);
            string fileExtension = this.AttachName.Substring(this.AttachName.LastIndexOf(".") + 1).ToLower();
            switch (fileExtension)
            {
                //case "pdf":
                //    this.IsInline = true;
                //    this.ContentType = "application/pdf";
                //    break;
                case "html":
                case "htm":
                    this.IsInline = true;
                    this.ContentType = "text/html";
                    break;
                default:
                    this.IsInline = false;
                    this.ContentType = "application/octet-stream";
                    break;
            }
            SetResponse();
        }

        /// <summary>
        /// 对附件返回进行填充
        /// </summary>
        public void SetResponse()
        {
            try
            {
                if (Utils.ConfigHelper.GetAppSettingValue("LoaclAttatch", "1") == "1")
                {
                    string filepath = Utils.ConfigHelper.GetAppSettingValue(Context.Request["filecat"]) + new Uri(this.AttachUrl).PathAndQuery.Replace("/", @"\");
                    filepath = HttpUtility.UrlDecode(filepath);
                    LogHelper.WriteLog("[文件下载开始:" + DateTime.Now.ToString() + "][用户:" + base.UserID + "][文件:" + filepath + "]");
                    LoadFile(this.ContentType, this.IsInline, this.AttachName, filepath);
                    LogHelper.WriteLog("[文件下载结束:" + DateTime.Now.ToString() + "][用户:" + base.UserID + "][文件:" + filepath + "]");
                }
                else
                {
                    LogHelper.WriteLog("[文件下载开始:" + DateTime.Now.ToString() + "][用户:" + base.UserID + "][文件:" + this.AttachUrl + "]");
                    SetResponse(this.ContentType, this.IsInline, this.AttachName, this.AttachUrl);
                    LogHelper.WriteLog("[文件下载结束:" + DateTime.Now.ToString() + "][用户:" + base.UserID + "][文件:" + this.AttachUrl + "]");
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("[文件下载异常:" + DateTime.Now.ToString() + "][用户:" + base.UserID + "][文件:" + this.AttachUrl + "][异常信息：" + ex.Message + "]");
                this.Context.Response.Write("文件下载出错，请联系管理员");
                this.Context.Response.Flush();
            }
            finally
            {
                this.Context.Response.End();
            }
        }
        /// <summary>
        /// 对附件返回进行填充
        /// </summary>
        /// <param name="contentType">application/octet-stream、application/pdf、text/plain</param>
        /// <param name="isInline">是否在线打开(android系统pdf时需要否)</param>
        /// <param name="attachName">文件下载后显示名称</param>
        /// <param name="attachUrl">附件绝对url</param>
        protected void SetResponse(string contentType, bool isInline, string attachName, string attachUrl)
        {
            WebClient wb = new WebClient();
            string proxyip=Utils.ConfigHelper.GetAppSettingValue("Proxy");
            if (!string.IsNullOrEmpty(proxyip))
            {
                WebProxy proxy = new WebProxy(proxyip, true);
                string userName = Utils.ConfigHelper.GetAppSettingValue("ProxyUserName");
                string userPassword = Utils.ConfigHelper.GetAppSettingValue("ProxyPassword");
                if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userPassword))
                {
                    proxy.Credentials = new NetworkCredential(userName, userPassword);
                }
                wb.Proxy = proxy;
            }
            wb.Encoding = Encoding.GetEncoding("gb2312");
            byte[] bytes = wb.DownloadData(attachUrl);

            this.Context.Response.Charset = "gb2312";
            this.Context.Response.ContentEncoding = wb.Encoding;

            this.Context.Response.Buffer = false;
            this.Context.Response.AddHeader("Content-Length", bytes.Length.ToString());

            string contentDisposition = isInline ? "inline" : "attachment";
            this.Context.Response.AddHeader("Content-Disposition", contentDisposition + ";filename=" + HttpUtility.UrlEncode(attachName, System.Text.Encoding.UTF8));
            this.Context.Response.ContentType = contentType;

            this.Context.Response.BinaryWrite(bytes);

            this.Context.Response.Flush();
        }

        /// <summary>
        /// 加载本地文件
        /// </summary>
        /// <param name="contentType"></param>
        /// <param name="isInline"></param>
        /// <param name="attachName"></param>
        /// <param name="filepath"></param>
        protected void LoadFile(string contentType, bool isInline, string attachName, string filepath)
        {
            Byte[] bytes = File.ReadAllBytes(filepath);

            this.Context.Response.Charset = "gb2312";
            this.Context.Response.ContentEncoding = Encoding.GetEncoding("gb2312");

            this.Context.Response.Buffer = false;
            this.Context.Response.AddHeader("Content-Length", bytes.Length.ToString());

            string contentDisposition = isInline ? "inline" : "attachment";
            this.Context.Response.AddHeader("Content-Disposition", contentDisposition + ";filename=" + HttpUtility.UrlEncode(attachName, System.Text.Encoding.UTF8));
            this.Context.Response.ContentType = contentType;

            this.Context.Response.BinaryWrite(bytes);

            this.Context.Response.Flush();
        }        
    }
}
